SORACOMのSDKを生成して使ってみた。 for AngularJS #soracom
はじめに
好物はインフラとフロントエンドのかじわらゆたかです。
本記事はSORACOM Advent Calendar 2015の8日目です。
7日目の延長で、生成したSDKを使ってみたといった軽めのネタを考えていた、そんな時期もありました。
SDKの生成・CORSによるアクセス制御に引っかかる。
前回のNode.jsとほぼ同一になります。
リポジトリ取得・モジュール取得・自動生成
$ git clone hogehogehoge $ npm install $ node angularGenerate.js soracom SDK for angular.js Generated
生成に成功すると以下のディレクトリに生成されたSDKが配置されます。
$ ls ./soracom-sdk/angularjs soracomSdk.js
生成されたSDKをAngular側から呼んでみます。
LoginCtrl.js
function LoginCtrl($scope,SoracomSDK,$log) { 'ngInject'; // ViewModel const vm = this; vm.doLogin = function(){ doLogin(); }; var doLogin = function(){ var option = {}; var formData = $scope.loginForm; var email = formData.mail.$modelValue; var password = formData.password.$modelValue; var soracomService = new SoracomSDK(option); var authRequest = { 'email' : email, 'password': password, 'tokenTimeoutSeconds':0 }; var req = {}; req.auth = authRequest; var promise = soracomService.auth(req); promise.then(successHandler); promise['catch'](failHandler); }; var successHandler = function(){ $log.debug('login success'); }; var failHandler = function(){ $log.debug('login fail'); }; }
Login.html
<form class="form-signin" name="loginForm"> <h2 class="form-signin-heading">Please sign in</h2> <label for="inputEmail" class="sr-only">Email address</label> <input type="email" name = "mail" id="inputEmail" class="form-control" placeholder="Email address" required autofocus ng-model="login.mail"> <label for="inputPassword" class="sr-only">Password</label> <input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required ng-model="login.password"> <div class="checkbox"> <label> <input type="checkbox" value="remember-me"> Remember me </label> </div> <button class="btn btn-lg btn-primary btn-block" type="submit" ng-click="login.doLogin()">Sign in</button> </form>
上記を動かしたところ、以下のようになりました。
フロントエンド開発でよくあるCORSによるアクセス制御で引っ掛かっています。
SORACOMのAPIが異なるドメインから呼び出される前提で作られていないため、
このようなエラーになっているものと想定できます。
アドベントカレンダーのネタがCORSによるアクセス制御でWEBブラウザ上からは呼べませんでした、
では流石にあかんと思ったので、呼べる方法を検討してみたいと思います。
要はWebブラウザからAPI直接呼ぶからエラーになるわけで、
それならば手前にサーバーを立てて呼べば良いのですが、それも芸がありません。
というわけで、API GatewayでSORACOMのAPIをラップして呼び出してみればと思い、実施してみました。
Amazon API Gatewayを用いたCORSによるアクセス制御回避
基本編
まずは、以下のエントリーを参考にラップしていきます。
Amazon API Gateway を使って AWS 以外のサービスの API をラップする | Developers.IO
その際、ResouceはラップするAPIと同一にしてください。
/auth をラップするAPIのResouceはauthとします。
また、Method同一に、Endpoint URLも対応するようにします。
以前、API GatewayCORSに対応するためには、以下の様な手順を踏む必要がありました。
Amazon API Gateway をクロスオリジンで呼び出す (CORS) | Developers.IO
11/3のAPI Gatewayの更新でCORSを有効にする機能が追加されました。
Amazon Web Services ブログ: 週刊AWS - 2015年11月2日
今回はその機能を使ってみたいと思います。
作成したResouceを選択し、EnableCORSを押下します。
その後、表示されたEnable CORS and replace existing CORS Headers を押下します。
最後の確認ダイアログもそのままYes,replace existing valuesを押下します。
上記のようにすることで、CORS対応のAPIを作ることができます。
リソースベースのルーティング
SORACOMのAPIをAPI Gatewayでラップするにあたり、
/groups/{group_id}といった形でURL内に操作対象のリソースを埋め込まれている場合、
以下のようにすることでラップすることが可能です。
- API GatewayのResouceとして、/groupsとその配下に/{group-id}を作成します。
-
GETメソッドを作成し、EndpoitURLのリソースを指定する個所を{}で囲みます。
今回の場合group-idがパラメータのため、
Endpointはhttps://api.soracom.io/v1/groups/{group-id} となります。 -
Integration Request内のURL Path ParametersでAdd pathを押下し、以下のように設定します。
Name | Mapped from |
---|---|
group-id | method.request.querystring.group-id |
HeaderへのRequestTokenの埋め込み
SORACOMのAPIを呼び出す際に、ほとんどのAPIでAPIKeyとTokenをHeaderに設定する必要があります。
SORACOM API 利用ガイド
上記のリソースベースのルーティングでラップした https://api.soracom.io/v1/groups/{group-id}
に対しても設定が必要な為、設定したいと思います。
今回の作例では、フロントからの呼び出しを容易にするため、フロントで設定するheaderはapiKeyとtokenとし、
API Gatewayの中で、soracom用のheader(X-Soracom-API-Key・X-Soracom-Token)に変換することにします。
- Method Request内にてHTTP Request Headers → Add Headerと進み、以下の項目を追加します。
Name | Mapped from |
---|---|
X-Soracom-API-Key | method.request.header.apiKey |
X-Soracom-Token | method.request.header.token |
- Integration Request内にてHTTP Headers内でAdd headerと進み、以下の項目を追加します。
Name | Mapped from |
---|---|
X-Soracom-API-Key | method.request.header.apiKey |
X-Soracom-Token | method.request.header.token |
- 最初に書いた基本編に基づき、作成したResouceをCORS対応にします。
その際今回はRequest HeaderにapiKeyとtokenが増えているので、その旨を記載する必要があります。
Enable CORSを押下後に、Access-Control-Allow-Headersの中にapiKeyとtokenを追記します。
また、自動生成したSDKがoperatoridという項目のRequestもするため、その旨も追記します。
設定が完了したら、Deploy APIを押下し、設定したAPIを使えるようにします。
実装例
生成したSDKで上記で作成したAPIを用いる際は、払いだされたAPIのURLをSDKに指定する必要があります。
ログインして、Headerに埋め込んでGroupの情報を参照するといった流れは以下になります。
LoginCtrl.js
function LoginCtrl($scope,SoracomSDK,$log) { 'ngInject'; // ViewModel const vm = this; var doLogin = function(){ var option = {'domain':'API Gatewayで払いだされたURL'}; var soracomService = new SoracomSDK(option); var formData = $scope.loginForm; var email = formData.mail.$modelValue; var password = formData.password.$modelValue; var authRequest = { 'email' : email, 'password': password, 'tokenTimeoutSeconds':0 }; var req = {}; req.auth = authRequest; var promise = soracomService.auth(req); promise.then(successHandler); promise['catch'](failHandler); }; var successHandler = function(result){ $log.debug('login success',result); getGroupInfo(result); }; var failHandler = function(){ $log.debug('login fail'); }; var getGroupInfo = function(soracomTokenObj){ var option = {'domain':'API Gatewayで払いだされたURL'}; var soracomService = new SoracomSDK(option); soracomService.setTokenObj(soracomTokenObj); var param = {}; param['group_id'] = '参照対象のGroup ID'; var promise = soracomService.get_group(param); promise.then(successGetGroupHandler); promise['catch'](failGetGroupHandler); }; var successGetGroupHandler = function(result){ vm.result = result; $log.debug('Get Group Info success',result); }; var failGetGroupHandler = function(){ $log.debug('Get Group Info fail'); }; vm.doLogin = doLogin; }
まとめ
AngularからSORACOMのAPIが簡単に呼べました、みたいなネタにするはずが、
API Gatewayを使ってSORACOM APIをラップするといった内容になってしまいました。
今回はSORACOMのAPIを対象にしましたが、
Swaggerが公開されているAPIならば同様の方法を用いることができるかと思います。